Java学习笔记之信息隐藏(Information Hiding)

好的类接口就像是冰山的尖儿一样,让类的大部分内容都不会暴露出来

什么是信息隐藏

信息隐藏指在设计和确定模块时,使得一个模块内包含的特定信息(过程或数据),对于不需要这些信息的其他模块来说,是不可访问的。

1972年,David Parnas 发表了一篇题为《论将系统分解为模块的准则》的论文首次让公众注意到信息隐藏这一概念。
信息隐藏式结构程序设计与面向对象设计的基础之一。在面向对象设计中,它又引出了封装和模块化的概念,并与抽象的概念紧密相关。
信息隐藏是软件的首要技术使命中格外重要的一种启发式方法,因为它强调的就是隐藏复杂度。

信息隐藏在设计的所有层次上都有很大作用:从用具名常量代替字面常量,到创建数据类型,再到类的设计、子程序的设计以及子系统的设计等等。

为什么要隐藏

  1. 隐藏复杂度:这样你就不用再去应付它,除非你要特别关注的时候;
  2. 隐藏变化源:这样当变化发生时,其影响就能被限制在局部范围内。复杂度的根源包括复杂的数据类型、文件结构、布尔判断以及晦涩的算法等等。

信息隐藏的障碍及建议

信息过度分散

案例1
描述:把具体数字(如100)直接写到程序中,这样会导致对它的引用过于分散
建议:可以将这个具体数字信息隐藏起来,写入一个叫 MAX_VALUE的常量中,如果需要更改常量的值,只需要改动一处即可


案例2:
描述:在系统内部到处都有与人机交互相关的内容,如果突然某一天要改变交互方式——如从图形用户界面变为命令行界面——那么所有与之相关的代码都需要改动
建议:可以将与人机交互逻辑集中到一个单独的类、包或者子系统中,这样,改动就不会给系统带来全局性的影响了


案例3
描述:比如一个在全局范围内都可以访问的、含有1000个元素的员工数据数组,如果程序直接使用该全局数组,那么关于该数据项的实现细节——比如它是一个数组,可以存放最多1000个元素这些信息——就会在程序中到处分散
建议:如果程序仅是通过访问器子程序(access routines)来使用该数据的话,就只有访问器子程序才知道其实现细节。

循环依赖

案例4
描述:A类中的子程序调用B类中的子程序,然后B类中的子程序又调用A类中的子程序,从而形成了循环依赖,导致系统难于测试。
建议:尽量避免循环依赖

把类内数据误认为全局变量

案例5
描述:为了避免全局数据可能带来的问题,可能会把类内数据误认为是全局数据并避免使用它,然而,全局变量会让你陷入很多编程陷阱,而类内数据可能带来的风险则要小得多。
建议:正确区分全局数据与类内数据,并恰当使用

说明:全局数据通常会受困于两类问题

  1. 子程序在全局数据之上执行操作,但却不知道还有其它子程序也在使用这些全局数据进行操作
  2. 子程序知道其他的子程序也在用全局数据进行操作,但却无法明确的知道都进行了哪些操作。

信息隐藏的价值

信息隐藏有着独特的启发力,它能够激发出有效的设计方案。信息隐藏同样有助于设计类的公开接口。在设计的所有层面上,都可以通过询问该隐藏些什么来促成好的设计决策。
养成问“我该隐藏些什么?”的习惯,你会惊奇的发现,有很多棘手的设计难题都会在你面前化解。

参考资料

《代码大全(第二版)》 第5章第3节 设计构造块:启发式方法